/*
 * @Description: 树结构操作JS
 * @Version: 1.0
 * @Autor: hekai
 * @Date: 2021-08-13 09:42:34
 * @LastEditors: hekai
 * @LastEditTime: 2021-11-17 16:52:51
 */
/**
 * @description:
 * @param {*} data 数据源
 * @param {*} id 子节点id 属性名
 * @param {*} parentId 父节点id 属性名
 * @param {*} children 子节点list属性名
 * @param {*} rootId 根节点id 值
 * @return {*}
 * @author: hekai
 */
export function handleTree(data, id = 'id', parentId = 'parentId', children = 'children', rootId = 0) {
  // 对源数据深度克隆
  const cloneData = JSON.parse(JSON.stringify(data))
  // 循环所有项
  let treeData = cloneData.filter(father => {
    let branchArr = cloneData.filter(child => {
      // 返回每一项的子级数组
      return father[id] === child[parentId]
    })
    if (branchArr.length > 0) {
      father[children] = branchArr
    }
    // 返回第一层
    return father[parentId] == rootId
  })
  return treeData
}

/**
 * @description: 获取传入子节点参数的id获取层级数据
 * @param {*} id 查找依据，可使用第三个属性改成key值
 * @param {*} key 查找依据的属性名
 * @param {*} parentId pid的属性名
 * @return {*} 1级-2级-3级-4级-5级
 * @author: hekai
 */
export function getLevelListByKey(data, currentId, key = 'id', parentId = 'parentId') {
  let topPid = '0' // 顶级父节点ID
  const resultList = [] // 结果
  let node = getTreeNodeByKey(data, currentId, key)
  resultList.push(node)
  if (node && node[parentId] !== topPid) {
    getLevelList(data, resultList, node[parentId], key, parentId)
    // 调整一下顺序，按照【1级-2级-3级】输出结果
    return resultList.reverse()
  }
  // 只有一级的时候，直接返回结果
  return resultList
}

function getLevelList(data, resultList, currentId, key, parentId = 'parentId') {
  let topPid = '0' // 顶级父节点ID
  let node = getTreeNodeByKey(data, currentId, key)
  resultList.push(node)
  if (node && node[parentId] && node[parentId] !== topPid) {
    getLevelList(data, resultList, node[parentId], key, parentId)
  }
  if (node[parentId] == topPid) {
    return resultList
  }
}

/**
 * @description: 根据key值查找树结构的节点
 * @param {*} list
 * @param {*} value 值
 * @param {*} key 查找的属性名
 * @return {*} 返回符合条件的此节点
 * @author: hekai
 */
export function getTreeNodeByKey(list, value, key = 'id') {
  for (let i in list) {
    if (list[i][key] == value) {
      return list[i]
    }
    if (list[i].children) {
      let node = getParentKey(list[i].children, value, key)
      if (node !== undefined) {
        return node[0]
      }
    }
  }
}

function getParentKey(list, value, key) {
  for (let i in list) {
    if (list[i][key] == value) {
      return [list[i]]
    }
    if (list[i].children) {
      let node = getParentKey(list[i].children, value, key)
      if (node !== undefined) {
        return node.concat(list[i])
      }
    }
  }
}

/**
 * @description: 根据id查找树结构的节点
 * @param {*} list
 * @param {*} id
 * @return {*} 返回符合条件的此节点
 * @author: hekai
 */
export function getTreeNodeById(list, id) {
  for (let i in list) {
    if (list[i].id == id) {
      return list[i]
    }
    if (list[i].children) {
      let node = getParentId(list[i].children, id)
      if (node !== undefined) {
        return node[0]
      }
    }
  }
}

function getParentId(list, id) {
  for (let i in list) {
    if (list[i].id == id) {
      return [list[i]]
    }
    if (list[i].children) {
      let node = getParentId(list[i].children, id)
      if (node !== undefined) {
        return node.concat(list[i])
      }
    }
  }
}

/**
 * @description: 获取树形结构的每一个节点的最后一个子节点
 * @param {*} list 树数据
 * @return {*} lastChildren 每一个节点的最后一个子节点数组
 * @author: hekai
 */
export function getLastChildren(list) {
  var lastChildren = []
  for (var i = 0; i < list.length; i++) {
    var chlist = list[i]
    if (!!chlist.children && chlist.children.length > 0) {
      getChildren(lastChildren, chlist.children)
    } else {
      lastChildren.push(chlist)
    }
  }
  return lastChildren
}

function getChildren(lastChildren, list) {
  for (var i = 0; i < list.length; i++) {
    var chlist = list[i]
    if (!!chlist.children && chlist.children.length > 0) {
      getChildren(lastChildren, chlist.children)
    } else {
      lastChildren.push(chlist)
    }
  }
}

/**
 * @description: 根据节点名字搜索查找树结构的节点，用于模糊查询树节点
 * @param {*} list
 * @param {*} val
 * @param {*} nameKey
 * @return {*} 返回符合条件的此节点数组
 * @author: hekai
 */
export function fuzzySearchTreeNodeByName(arr, value, nameKey) {
  let newarr = []
  arr.forEach(element => {
    if (element.children && element.children.length) {
      const ab = fuzzySearchTreeNodeByName(element.children, value, nameKey)
      const obj = {
        ...element,
        children: ab
      }
      if (ab && ab.length) {
        newarr.push(obj)
      }
    } else {
      if (element[nameKey].indexOf(value) > -1) {
        newarr.push(element)
      }
    }
  })
  return newarr
}

/**
 * @description: 树结构，获取children下的第一个节点，一直递归获取到最深且满足条件的第一个，如果没有子节点，则返回当前Node
 * @param {*} treeNode
 * @param {*} filterFunction 可选，条件筛选函数
 * @return {*} 返回符合条件的此节点数组
 * @author: hekai
 */
export function getFirstDeepChildren(treeNode, filterFunction) {
  let result = []

  function each(node, firstDeepNode) {
    if (node.children && node.children.length !== 0) {
      if (filterFunction) {
        // 去掉不符合筛选条件的node
        node.children = node.children.filter((item) => {
          return filterFunction(item)
        })
      }
      each(node.children[0], firstDeepNode)
    }
    result.push(node)
  }

  each(treeNode, result)
  return result[0]
}

/**
 * 根据id批量删除
 * @param data 树数据
 * @param value 要删除节点的id
 * @param key 依据的key值，默认为id
 * @returns {*}
 */
export function deleteTreeNodeByKey(data, value, key = 'id') {
  let newData = data.filter(x => x[key] !== value)
  newData.forEach(x => x.children && (x.children = deleteTreeNodeByKey(x.children, value, key)))
  return newData
}

/**
 * 根据ids批量删除
 * @param data 树数据
 * @param valueList id的list数组
 * @param key 依据的key值，默认为id
 * @returns {*}
 */
export function deleteBatchTreeNodeByKey(data, valueList, key = 'id') {
  // 过滤掉：id包含在valueList内的节点
  let newData = data.filter(x => !valueList.some(item => item === x[key]))
  newData.forEach(x => x.children && (x.children = deleteBatchTreeNodeByKey(x.children, valueList, key)))
  return newData
}

// 做这个class，只是为了做链式调用
// 用法：let treeNode = new TreeNode();
//     treeNode.getNodeByKey(this.treeData, oldName, 'folderName').then((node) => {})
export class TreeNode {
  constructor() {
    this.list = []
    this.value = ''
    this.key = 'id'
  }

  getNodeByKey(list, value, key = 'id') {
    this.list = list
    this.value = value
    this.key = key
    return this
  }

  then(callback) {
    this.findTreeNodeByKey(this.list, this.value, this.key, callback)
  }

  /**
   * @description: 根据key值查找树结构的节点,支持回调函数
   * @param {*} list
   * @param {*} value 值
   * @param {*} key 查找的属性名
   * @param {*} callback 找到节点后的回调函数
   * @return {*} 返回符合条件的此节点
   * @author: hekai
   */
  findTreeNodeByKey(list, value, key = 'id', callback) {
    for (let i in list) {
      if (list[i][key] == value) {
        callback(list[i])
        return list[i]
      }
      if (list[i].children) {
        let node = this.findParentKey(list[i].children, value, key, callback)
        if (node !== undefined) {
          return node[0]
        }
      }
    }
  }

  findParentKey(list, value, key, callback) {
    for (let i in list) {
      if (list[i][key] == value) {
        callback(list[i])
        return [list[i]]
      }
      if (list[i].children) {
        let node = this.findParentKey(list[i].children, value, key, callback)
        if (node !== undefined) {
          return node.concat(list[i])
        }
      }
    }
  }
}

// 获取某节点的所有子节点的某个属性值，默认是id
export function getChildrenKeyList(data, key = 'id') {
  if (!!!data) {
    return []
  }

  const result = []

  function getChildren(data) {
    data.forEach(item => {
      if (!item.children) {
        result.push(item[key])
      } else {
        getChildren(item.children)
      }
    })
  }

  getChildren(data)
  return result
}


/**
 * 遍历树形结构，并根据func生成新节点，你可以理解为Tree的数组map函数。
 * @param tree {array} 树形数据
 * @param func {function} 更新函数
 * @param children {string} children的属性名
 * @returns {array}
 */
export function mapTree(tree, func, children = 'children') {
  try {
    let newData = tree.map((node) => {
      return func({ ...node })
    })
    newData.forEach(node => node[children] && (node[children] = mapTree(node[children], func, children)))
    return newData
  } catch (e) {
    console.error('mapTree.js [easy-project-vue error]:', e)
    return []
  }
}
